package com.rain.rainspringboot3.encryption.service;


import com.rain.rainspringboot3.desensitize.core.DesensitizationHandlerFactory;
import com.rain.rainspringboot3.desensitize.core.base.annotation.DesensitizeBy;
import com.rain.rainspringboot3.desensitize.core.base.handler.DesensitizationHandler;
import com.rain.rainspringboot3.desensitize.core.slider.handler.AbstractSliderDesensitizationHandler;
import com.rain.rainspringboot3.desensitize.core.util.DesensitizeAnnotationHelper;
import com.rain.rainspringboot3.encryption.annotation.EncryptField;
import com.rain.rainspringboot3.encryption.entity.SensitiveData;
import com.rain.rainspringboot3.encryption.exception.EncryptionException;
import com.rain.rainspringboot3.encryption.factory.EncryptFactory;
import com.rain.rainspringboot3.encryption.strategy.EncryptionStrategy;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 加密服务实现
 * 负责处理对象的加密和解密逻辑
 */
@Service
@Slf4j
@AllArgsConstructor
public class EncryptionServiceImpl implements EncryptionService {

    public static final Map<String, String> KEY_CACHE_MAP = new ConcurrentHashMap<>();

    private static final String CACHE_KEY_PREFIX = "sensitive:";

    private final Map<String, EncryptFactory> encryptFactories;

    private final SensitiveDataService sensitiveDataService;

    private final CacheService cacheService;

    private final DesensitizationHandlerFactory handlerFactory;

    @Override
    @Transactional
    @SuppressWarnings("all")
    public <T> T encryptObject(T object) {
        if (object == null) {
            return null;
        }

        Class<?> clazz = object.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            if (shouldSkipField(field)) {
                continue;
            }

            if (field.isAnnotationPresent(EncryptField.class)) {
                processFieldEncryption(object, field);
            }
        }
        return object;
    }

    private boolean shouldSkipField(Field field) {
        int modifiers = field.getModifiers();
        return Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers);
    }

    /**
     * 对字段进行加密处理
     *
     * @param object          对象
     * @param field           字段
     * @return 加密后的敏感数据ID
     */
    @SuppressWarnings("all")
    private <T> void processFieldEncryption(T object, Field field) {
        EncryptField encryptField = field.getAnnotation(EncryptField.class);
        boolean accessible = field.isAccessible();
        try {
            field.setAccessible(true);
            Object value = field.get(object);

            if (value == null) {
                return;
            }

            Map<String, String> prefixAndSuffixMap = null;

            if (DesensitizeAnnotationHelper.hasDesensitizeAnnotation(field)) {
                try {
                    Annotation annotation = DesensitizeAnnotationHelper.getDesensitizeAnnotation(field);
                    DesensitizeBy desensitizeBy = annotation.annotationType().getAnnotation(DesensitizeBy.class);
                    if (desensitizeBy != null) {
                        Class<? extends DesensitizationHandler> handlerClass = desensitizeBy.handler();
                        DesensitizationHandler handler = handlerFactory.getHandler(handlerClass);
                        if (handler != null) {
                            prefixAndSuffixMap = processDesensitizationConfig(field, value, annotation, handler);
                        }
                    }
                } catch (Exception e) {
                    throw new EncryptionException("脱敏配置处理失败: " + field.getName(), e);
                }
            }
            Long sensitiveDataId = encryptField(value.toString(), encryptField, object, prefixAndSuffixMap != null ? prefixAndSuffixMap : Collections.emptyMap());

            Class<?> fieldType = field.getType();
            if (fieldType == String.class) {
                field.set(object, sensitiveDataId.toString());
            } else if (fieldType == Long.class || fieldType == long.class) {
                field.set(object, sensitiveDataId);
            } else {
                throw new EncryptionException("不支持的字段类型: " + fieldType.getName() + " 字段名: " + field.getName());
            }
        } catch (IllegalAccessException e) {
            throw new EncryptionException("字段加密失败: " + field.getName(), e);
        } finally {
            // 恢复原访问权限
            field.setAccessible(accessible);
        }
    }


    /**
     * 处理字段的脱敏配置
     *
     * @param field      字段
     * @param value      字段值
     * @param annotation 脱敏注解
     * @param handler    脱敏处理器
     * @return 脱敏配置
     */
    @SuppressWarnings("all")
    private Map<String, String> processDesensitizationConfig(Field field, Object value, Annotation annotation, DesensitizationHandler handler) {
        try {
            if (handler instanceof AbstractSliderDesensitizationHandler) {
                // 滑动脱敏处理器
                AbstractSliderDesensitizationHandler sliderHandler = (AbstractSliderDesensitizationHandler) handler;
                return sliderHandler.getPrefixAndSuffix(value.toString(), annotation);
            } else {
                // 其他类型的脱敏处理器
                return (Map<String, String>) handler.getPrefixAndSuffix(value.toString(), annotation);
            }
        } catch (Exception e) {
            log.error("脱敏配置处理失败: {}, 错误: {}", field.getName(), e.getMessage());
            return Collections.emptyMap();
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public Long encryptField(String plainText, EncryptField encryptField, Object contextObject, Map<String, String> prefixAndSuffixMap) {
        // 1. 获取加密策略
        EncryptFactory factory = encryptFactories.get(encryptField.factory().getSimpleName());
        if (factory == null) {
            // 使用默认AES策略
            factory = encryptFactories.get("AESEncryptFactory");
        }

        EncryptionStrategy strategy = factory.createStrategy();

        // 2. 处理前缀后缀
        String prefix = Optional.ofNullable(prefixAndSuffixMap).map(map -> map.get("prefix")).orElse("");
        String suffix = Optional.ofNullable(prefixAndSuffixMap).map(map -> map.get("suffix")).orElse("");
        String key = null;
        if (encryptField.encrypt()) {
            key = strategy.generateKey();
        }

        // 3.1 判断数据是否存在
        SensitiveData existSensitive = sensitiveDataService.getByPrefixAndSuffixAndCipherText(prefix, suffix, plainText);
        if (existSensitive != null) {
            return existSensitive.getId();
        }

        // 3.2 加密数据
        String cipherText = strategy.encrypt(plainText, key);

        // 4. 存储到敏感数据表
        SensitiveData sensitiveData = new SensitiveData();
        sensitiveData.setPrefix(prefix);
        sensitiveData.setSuffix(suffix);
        sensitiveData.setCipherText(cipherText);
        sensitiveData.setEncryptionAlgorithm(factory.getAlgorithmName());
        sensitiveData.setDataType(encryptField.type().name());
        // 注意：密钥需要安全存储
        sensitiveData.setEncryptionKey(key);
        sensitiveDataService.saveData(sensitiveData);

        // 5. 缓存处理
        if (encryptField.cacheable()) {
            String cacheKey = CACHE_KEY_PREFIX + sensitiveData.getId();
            cacheService.saveString(cacheKey, plainText, encryptField.cacheExpire(), encryptField.cacheTimeUnit());

        }

        return sensitiveData.getId();
    }

    @Override
    public <T> T decryptObject(T object) {
        if (object == null) {
            return null;
        }
        // 如果是集合类型，递归处理每个元素
        if (object instanceof Collection<?> collection) {
            for (Object item : collection) {
                // 递归处理集合中的每个对象
                decryptObject(item);
            }
            return object;
        }
        Class<?> clazz = object.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(EncryptField.class)) {
                try {
                    field.setAccessible(true);
                    Object value = field.get(object);
                    EncryptField encryptField = field.getAnnotation(EncryptField.class);
                    if (value != null) {
                        // 解密处理
                        String plainText = decryptField(Long.parseLong(value.toString()), encryptField);
                        // 将字段值替换为解密后的明文
                        field.set(object, plainText);
                    }
                } catch (Exception e) {
                    throw new EncryptionException("字段解密失败: " + field.getName(), e);
                }
            }
        }
        return object;
    }

    @Override
    public String decryptField(Long sensitiveDataId, EncryptField encryptField) {
        // 1. 尝试从缓存获取
        String cacheKey = CACHE_KEY_PREFIX + sensitiveDataId;
        String cachedValue = cacheService.getString(cacheKey);
        if (cachedValue != null) {
            return cachedValue;
        }

        // 2. 查询数据库
        SensitiveData sensitiveData = sensitiveDataService.getById(sensitiveDataId);
        if (sensitiveData == null) {
            throw new EncryptionException("敏感数据不存在, ID: " + sensitiveDataId);
        }

        // 3. 获取加密策略,解密数据
        String plainText = getPlainText(sensitiveData);
        if (encryptField.cacheable()) {
            // 4. 更新缓存
            cacheService.saveString(cacheKey, plainText, encryptField.cacheExpire(), encryptField.cacheTimeUnit());
        }

        return plainText;
    }

    @Override
    public String getPlainText(SensitiveData sensitiveData) {
        // 3.1 获取加密策略
        EncryptFactory factory = encryptFactories.values().stream().filter(f -> f.getAlgorithmName().equals(sensitiveData.getEncryptionAlgorithm())).findFirst().orElseThrow(() -> new EncryptionException("不支持的加密算法: " + sensitiveData.getEncryptionAlgorithm()));

        EncryptionStrategy strategy = factory.createStrategy();
        String key = StringUtils.isBlank(sensitiveData.getEncryptionKey()) ? KEY_CACHE_MAP.get(sensitiveData.getEncryptionAlgorithm()) : sensitiveData.getEncryptionKey();

        // 3.2 解密数据
        return strategy.decrypt(sensitiveData.getCipherText(), key);
    }


    @Override
    public Map<Long, String> batchDecryptFields(Set<Long> sensitiveDataIds) {
        return Map.of();
    }
}